package research.ui.editors;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.forms.widgets.TableWrapData;

import research.domain.FilmType;
import research.domain.Formula;
import research.domain.Parameter;
import research.domain.ParameterValue;
import research.domain.Production;
import research.domain.Sample;
import research.entity.Entity;
import research.entity.EntityFactory;
import research.entity.EntityType;
import research.model.CalanderHierarchy;
import research.model.EntityListContentProvider;
import research.model.FilmTypeHierarchy;
import research.model.ListHierarchy;
import research.model.SampleHierarchy;
import research.persistence.PersistenceManager;
import research.ui.editors.input.EntityEditorInput;
import research.ui.editors.tableeditors.sample.SampleTableEditor;

public class SampleEditor extends FormEntityEditor {
	public static String ID = "research.ui.editors.SampleEditor";
	
	private Text name;
	private ComboViewer production;
	private ComboViewer formula;
	private ComboViewer filmType;
	
	private SampleTableEditor valuesEditor;
	private List<Entity> values;
	private List<Entity> initValues;

	private Section recommended;
	Composite oldRecommended = null;
	
	private Sample getEntity() {
		return (Sample) entity;
	}

	@Override
	protected boolean checkInputEntityType(EntityEditorInput input) {
		return input.getEntity().getType().equals(EntityType.Sample);
	}

	@Override
	protected void fill() {
		this.name.setText(this.getEntity().getName());
		
		setComboEntity(production, this.getEntity().getProduction());
		setComboEntity(formula, this.getEntity().getFormula());
		setComboEntity(filmType, this.getEntity().getFilmType());

		updateTable(values);
		updateRecommended();
	}

	@Override
	protected void initialize() {
		if (!isNewEntity()) {
			values = PersistenceManager.getInstance().getDataSource().getChildren(getEntity(), new SampleHierarchy());
			initValues = PersistenceManager.getInstance().getDataSource().getChildren(getEntity(), new SampleHierarchy());
		} else {
			values = new ArrayList<Entity>();
			initValues = new ArrayList<Entity>();
		}
	}
	
	@Override
	protected void persist() {
		
		for (Entity oldpar : initValues) {
			Entity value = null;
			for (Entity newpar : valuesEditor.getEntityList().getEntities()) {
				if (newpar.equals(oldpar))
					value = newpar;
			}
			
			if (value == null || Double.isNaN(((ParameterValue) value).getValue())) {
				getPersistenceManager().remove(oldpar);
			}
		}

		for (Entity par : valuesEditor.getEntityList().getEntities()) {
			ParameterValue val = (ParameterValue) par;
			if (val.getParameter() != null && !Double.isNaN(val.getValue())) {
				val.setSample(getEntity());
				getPersistenceManager().persist(val);
			}
		}
	}

	@Override
	protected boolean readAndValidate() {
		this.getEntity().setName(this.name.getText());

		Production res = (Production) getComboEntity(production);
		Formula formul = (Formula) getComboEntity(formula);
		FilmType type = (FilmType) getComboEntity(filmType);
		
		for (Entity par : valuesEditor.getEntityList().getEntities()) {
			ParameterValue val = (ParameterValue) par;
			if (!Double.isNaN(val.getValue()))
				if (val.getValue() < val.getParameter().getLow() || val.getValue() > val.getParameter().getHigh()) {
					if (!MessageDialog.openQuestion(getSite().getShell(), "Error", "Значение параметра выходит за рамки ограничений для данного типа оборудования:\n" + val.getParameter().getName() + "\nХотите ли вы использовать это значение?"))
						return false;
				}
		}

		if (res == null) {
			MessageDialog.openWarning(getSite().getShell(), "Error",
					"Выберите производство");
			return false;
		}
		if (formul == null) {
			MessageDialog.openWarning(getSite().getShell(), "Error",
					"Выберите рецептуру");
			return false;
		}

		this.getEntity().setProduction(res);
		this.getEntity().setFormula(formul);
		this.getEntity().setFilmType(type);

		return validateText(name);
	}

	@Override
	protected void renderForm() {
		TableWrapData td;
		Label label;
		Section section;
		Composite composite;
		GridData gd;
		
		/*
		 * Production
		 */
		section = toolkit.createSection(form.getBody(), Section.TITLE_BAR);
		td = new TableWrapData(TableWrapData.FILL);
		section.setLayoutData(td);
		section.setText("Происхождение:");
		composite = toolkit.createComposite(section);
		composite.setLayout(new GridLayout(2, false));
		section.setClient(composite);
		gd = new GridData();
		label = toolkit.createLabel(composite, "Производство*:");
		label.setLayoutData(gd);
		gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL);
		production = new ComboViewer(composite, SWT.DROP_DOWN | SWT.READ_ONLY);
		production.setContentProvider(new EntityListContentProvider(new ListHierarchy(EntityType.Production), false));
		production.setLabelProvider(new LabelProvider());
		production.setInput(PersistenceManager.getInstance());
		gd.widthHint = 100;
		production.getCombo().setLayoutData(gd);
		production.getCombo().addModifyListener(getTextModifyListener());
		
		/*
		 * Formula
		 */
		gd = new GridData();
		label = toolkit.createLabel(composite, "Рецептура*:");
		label.setLayoutData(gd);
		gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL);
		formula = new ComboViewer(composite, SWT.DROP_DOWN | SWT.READ_ONLY);
		formula.setContentProvider(new EntityListContentProvider(new ListHierarchy(EntityType.Formula), false));
		formula.setLabelProvider(new LabelProvider());
		formula.setInput(PersistenceManager.getInstance());
		gd.widthHint = 100;
		formula.getCombo().setLayoutData(gd);
		formula.getCombo().addModifyListener(getTextModifyListener());
		
		/*
		 * Film Type
		 */
		gd = new GridData();
		label = toolkit.createLabel(composite, "Тип пленки:");
		label.setLayoutData(gd);
		gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL);
		filmType = new ComboViewer(composite, SWT.DROP_DOWN | SWT.READ_ONLY);
		filmType.setContentProvider(new EntityListContentProvider(new ListHierarchy(EntityType.FilmType), true));
		filmType.setLabelProvider(new LabelProvider());
		filmType.setInput(PersistenceManager.getInstance());
		gd.widthHint = 100;
		filmType.getCombo().setLayoutData(gd);
		filmType.getCombo().addModifyListener(getTextModifyListener());
		
		filmType.addSelectionChangedListener(new ISelectionChangedListener() {
			public void selectionChanged(SelectionChangedEvent event) {
				updateRecommended();
			}
		});

		/*
		 * Name
		 */
		section = toolkit.createSection(form.getBody(), Section.TITLE_BAR);
		td = new TableWrapData(TableWrapData.FILL_GRAB);
		section.setLayoutData(td);
		section.setText("Название*");
		composite = toolkit.createComposite(section);
		composite.setLayout(new GridLayout(1, false));
		section.setClient(composite);
		gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL);
		name = toolkit.createText(composite, "",
				SWT.BORDER);
		gd.widthHint = 100;
		name.setLayoutData(gd);
		name.addModifyListener(getNameModifyListener());
		
		/*
		 * Values
		 */
		section = toolkit.createSection(form.getBody(), Section.TITLE_BAR
				| Section.TWISTIE | Section.EXPANDED);
		td = new TableWrapData(TableWrapData.FILL);
		td.heightHint = 400;
		section.setLayoutData(td);
		section.setText("Контроль технологических параметров");
		composite = toolkit.createComposite(section);
		section.setClient(composite);
		valuesEditor = new SampleTableEditor(composite);
		
		filmType.getCombo().addModifyListener(new CalanderModifyListener());
		production.getCombo().addModifyListener(new CalanderModifyListener());

		/*
		 * Recommended tests
		 */
		recommended = toolkit.createSection(form.getBody(), Section.TITLE_BAR
				| Section.TWISTIE | Section.EXPANDED);
		td = new TableWrapData(TableWrapData.FILL);
		recommended.setLayoutData(td);
		recommended.setText("Добавить рекомендуемое испытание");
		composite = toolkit.createComposite(recommended);
		recommended.setClient(composite);
		oldRecommended = composite;
	}
	
	private void updateRecommended() {
		oldRecommended.dispose();
		oldRecommended = toolkit.createComposite(recommended);
		recommended.setClient(oldRecommended);
		oldRecommended.setLayout(new GridLayout(1, false));
		
		FilmType film = (FilmType) getComboEntity(filmType);
		if (film != null) {
			if (film.isHasStrength())
				createAddLink(EntityType.Strength, oldRecommended);
			if (film.isHasViscosity())
				createAddLink(EntityType.Viscosity, oldRecommended);
			if (film.isHasPhoto())
				createAddLink(EntityType.Photo, oldRecommended);
			if (film.isHasScratch())
				createAddLink(EntityType.Scratch, oldRecommended);
			if (film.isHasStabilizer())
				createAddLink(EntityType.SampleStabilizer, oldRecommended);
		}
		form.getBody().layout(true);
	}
	
	private void updateTable(List<Entity> values) {
		List<Entity> parameters = new ArrayList<Entity>();
		Production cal = (Production) ((StructuredSelection)production.getSelection()).getFirstElement();
		if (cal != null && cal.getCalander() != null) {
			parameters = PersistenceManager.getInstance().getDataSource().getChildren(cal.getCalander(), new CalanderHierarchy());
		}
		
		List<Entity> input = new ArrayList<Entity>();
		for (Entity param : parameters) {
			Parameter p = (Parameter) param;
			ParameterValue value = null;
			for (Entity v : values) {
				if (((ParameterValue) v).getParameter().equals(p))
					value = (ParameterValue) v;
			}
			
			if (value == null) {
				value = (ParameterValue) EntityFactory.getNew(EntityType.ParameterValue);
				value.setParameter(p);
				value.setValue(Double.NaN);
			}
			
			input.add(value);
		}

		FilmType type = (FilmType) getComboEntity(filmType);
		List<Entity> defaultValues = new ArrayList<Entity>();
		if (type != null)
			defaultValues = PersistenceManager.getInstance().getDataSource().getChildren(type, new FilmTypeHierarchy());
		
		valuesEditor.setDefaultValues(defaultValues);
		valuesEditor.setInput(input);
		valuesEditor.addModifyListener(getEntityTableListener());
	}
	
	public class CalanderModifyListener implements ModifyListener {
		@Override
		public void modifyText(ModifyEvent e) {
			updateTable(values);
		}
	}

}
